import {App} from "./App";
import {Mat4, Quat, toRadian, Vec3} from "../../../src/math";
import {Camera} from "./Camera";
import {Mesh} from "./Mesh";
import {Bone, SkinMesh, SkinVertex} from "./skeletal";

function initBones(){
    // for test
    // 手动建立层次结构
    let boneRoot = new Bone(new Vec3(), new Quat());

    let bone1 = new Bone(new Vec3(0.2, 0, 0), new Quat());
    boneRoot.add(bone1);

    let bone21 = new Bone(new Vec3(0.1, 0.1, 0), new Quat());
    let bone22 = new Bone(new Vec3(0.1, -0.1, 0), new Quat());
    bone1.add(bone21);
    bone1.add(bone22);

    //--------------
    // 创建 Mesh顶点
    let a = new SkinVertex(new Vec3(-0.1,0.1,0));
    a.addAffectBone(boneRoot,1);

    let b = new SkinVertex(new Vec3(0.2,0.1,0));
    b.addAffectBone(bone1,0.8);
    b.addAffectBone(bone21,0.2);

    let c = new SkinVertex(new Vec3(0.4,0.2,0));
    c.addAffectBone(bone1,0.2);
    c.addAffectBone(bone21,0.8);

    let d = new SkinVertex(new Vec3(0.5,0.15,0));
    d.addAffectBone(bone21,0.8);
    d.addAffectBone(bone22,0.2);

    let e = new SkinVertex(new Vec3(0.35,0,0));
    e.addAffectBone(bone21,0.5);
    e.addAffectBone(bone22,0.5);

    let f = new SkinVertex(new Vec3(0.5,-0.15,0));
    f.addAffectBone(bone21,0.2);
    f.addAffectBone(bone22,0.8);

    let g = new SkinVertex(new Vec3(0.4,-0.2,0));
    g.addAffectBone(bone22,1);

    let h = new SkinVertex(new Vec3(0.2,-0.1,0));
    h.addAffectBone(bone22,0.8);
    h.addAffectBone(bone22,0.2);

    let i = new SkinVertex(new Vec3(-0.1,-0.1,0));
    i.addAffectBone(boneRoot,1);

    let skinMesh = new SkinMesh([a,b,c,d,e,f,g,h,i]);
    return {
        boneRoot,
        skinMesh,
    };
}

// 每一帧都要更新骨头位置
function updateBoneData(boneRoot:Bone) {
    let posArr = [];
    let lastLevelNodes = boneRoot._children;
    let nextLevelNodes = [];
    while (lastLevelNodes.length > 0) {
        let len = lastLevelNodes.length;
        let idx = 0;
        while (idx < len) {
            let curNode = lastLevelNodes[idx];

            let parent = curNode._parent!!;
            let pPos = parent.vertexPos;
            posArr.push(pPos.x, pPos.y, pPos.z);

            let cPos = curNode.vertexPos;
            posArr.push(cPos.x, cPos.y, cPos.z);

            idx++;
            if (curNode._children.length > 0) {
                nextLevelNodes.push(...curNode._children);
            }
        }
        lastLevelNodes = nextLevelNodes;
        nextLevelNodes = [];
    }
    return posArr;
}


let boneVAO: WebGLVertexArrayObject = -1;
let boneVBO: WebGLBuffer = -1;
let typedArr :Float32Array | null = null;

export class Scene {
    camera: Camera;
    mesh: Mesh;
    _worldMat = new Mat4();
    boneRoot:Bone;
    skinMesh:SkinMesh;
    public constructor() {
        this.camera = new Camera();
        this.camera.position = new Vec3(0, 0, 2);
        let v = new Float32Array([
            0, 1, 0,
            -1, 0, 0,
            1, 0, 0
        ]);
        this.mesh = new Mesh(v);
        let {boneRoot,skinMesh} = initBones();
        this.boneRoot = boneRoot;
        this.skinMesh = skinMesh;
    }

    init() {
        let app = App.instance();
        let gl = app.gl;
        gl.clearColor(0, 0, 0, 1);
        gl.viewport(0, 0, app.width, app.height);
    }

    frame() {
        this.camera.update();

        this.boneRoot.rotateZ(1);
        this.boneRoot._children[0].rotateZ(2);

        this.boneRoot.updateBoneMatrix(Mat4.IDENTITY);

        let gl = App.instance().gl;
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        // this.mesh.draw(gl, this.camera);

        // 绘制出 bone
        this.drawBone(gl);

        // 绘制出静态的mesh
        this.skinMesh.render(gl,this.camera);
    }

    drawBone(gl:WebGL2RenderingContext){
        let arr = updateBoneData(this.boneRoot);
        if (!typedArr){
            typedArr = new Float32Array(arr);
        }else{
            typedArr.set(arr);
        }

        let shader = App.instance().shaderCache.get('line');
        shader.bind();

        if (boneVAO < 0) {
            boneVAO = gl.createVertexArray() as WebGLVertexArrayObject;
        }
        gl.bindVertexArray(boneVAO);
        if (boneVBO < 0) {
            boneVBO = gl.createBuffer() as WebGLBuffer;
        }
        gl.bindBuffer(gl.ARRAY_BUFFER,boneVBO);
        gl.bufferData(gl.ARRAY_BUFFER,typedArr,gl.DYNAMIC_DRAW);
        let pos = shader.attribs['a_position'];
        gl.enableVertexAttribArray(pos);
        gl.vertexAttribPointer(pos,3,gl.FLOAT,false,0,0);

        shader.setMat4('u_projMatrix',this.camera.projMat);
        shader.setMat4('u_vmMatrix',this.camera.viewMat);
        gl.drawArrays(gl.LINES,0,typedArr.length/3);
        gl.bindVertexArray(null);
        shader.unbind();
    }
}
